# -*- coding: utf-8 -*-
from dataclasses import dataclass, field, fields, MISSING
from datetime import datetime
from typing import Any, Dict, List, Optional, Union

@dataclass
class BaseRequest:
    @classmethod
    def from_dict(cls, data: Dict[str, Any]):
        """从字典创建请求对象并校验必填字段，自动转换 datetime 类型"""
        missing_fields = []
        kwargs = {}
        
        for field in fields(cls):
            field_name = field.name
            value = data.get(field_name)
            
            # 检查必填字段
            is_required = (field.default == MISSING and field.default_factory == MISSING)
            if is_required and value is None:
                missing_fields.append(field_name)
                continue

            # 处理 datetime 类型字段
            if value is not None:
                if field.type == datetime or field.type == Optional[datetime] or (hasattr(field.type, '__origin__') and getattr(field.type, '__origin__', None) is datetime):
                    try:
                        # 支持常见的日期时间格式
                        for fmt in ['%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%S', '%Y-%m-%d']:
                            try:
                                value = datetime.strptime(value, fmt)
                                break
                            except ValueError:
                                continue
                        else:
                            raise ValueError(f"无效的日期时间格式: {value}")
                    except Exception as e:
                        raise ValueError(f"字段 {field_name} 日期解析失败: {e}")

            kwargs[field_name] = value

        if missing_fields:
            raise ValueError(f"缺少必填参数: {', '.join(missing_fields)}")
            
        return cls(**kwargs)

@dataclass
class LoginRequest(BaseRequest):
    username: str  # 必填
    password: str  # 必填

@dataclass
class CreateTeacherRequest(BaseRequest):
    position: str  # 教师职位，对应 teachers.position
    name: str      # 教师姓名
    admin_password: str  # 管理员口令（验证用）

@dataclass
class TeacherAccountRegisterRequest(BaseRequest):
    username: str
    password: str
    teacher_password: str

@dataclass
class SetHeadTeacherRequest(BaseRequest):
    class_id: int
    teacher_id: int
    admin_password: str

@dataclass
class ListClassesRequest(BaseRequest):
    is_graduated: int  # 0=在校, 1=已毕业

@dataclass
class ListTeachersRequest(BaseRequest):
    name: Optional[str] = None  # 教师姓名（部分匹配，可选）
    class_id: Optional[int] = None  # 负责班级ID（可选）

@dataclass
class CreateStudentRequest(BaseRequest):
    student_id: int       # 学生学号
    name: str             # 学生姓名
    class_id: int         # 所在班级ID
    teacher_password: str

@dataclass
class ChangePasswordRequest(BaseRequest):
    old_password: str
    new_password: str

@dataclass
class ResetStudentPasswordRequest(BaseRequest):
    student_id: int       # 学生用户ID（users.id）
    new_password: str     # 新密码
    admin_password: str   # 管理员/教师口令

@dataclass
class ForgotPasswordRequest(BaseRequest):
    admin_password: str  # 管理员或教师口令
    new_password: str    # 新密码

@dataclass
class EditTeacherRequest(BaseRequest):
    user_id: int                # 教师用户ID
    admin_password: str         # 管理员口令
    name: Optional[str] = None  # 教师姓名（可选）
    position: Optional[str] = None  # 教师职位（可选）
    teacher_password: Optional[str] = None  # 教师新口令（可选)

@dataclass
class SetSubjectTeacherRequest(BaseRequest):
    class_id: int
    teacher_id: int
    subject: str
    admin_password: str
    id: Optional[int] = None  # 指定编辑条目 (可选)

@dataclass
class GetSubjectTeacherRequest(BaseRequest):
    class_id: int

@dataclass
class ListStudentsRequest(BaseRequest):
    class_id: Optional[int] = None    # 班级ID（teacher必传）
    name: Optional[str] = None        # 学生姓名（模糊匹配）
    has_group: Optional[int] = None   # 是否加入小组

@dataclass
class UpdateStudentRequest(BaseRequest):
    user_id: int                # 学生用户ID
    admin_password: str         # 教师/管理员口令
    name: Optional[str] = None  # 学生姓名
    username: Optional[str] = None  # 学生登录账号
    password: Optional[str] = None  # 学生登录密码
    class_id: Optional[int] = None  # 学生所在班级
    student_id: Optional[str] = None  # 学生学号
    school_position: Optional[str] = None # 学校职务
    class_position: Optional[str] = None  # 班级职务

@dataclass
class CreateStudyGroupRequest(BaseRequest):
    name: str   # 学习小组名称
    class_id: int  # 所属班级ID

@dataclass
class UpdateStudyGroupRequest(BaseRequest):
    group_id: int               # 小组ID
    name: Optional[str] = None  # 新的小组名称
    class_id: Optional[int] = None  # 新的所属班级ID

@dataclass
class AddStudentsToGroupRequest(BaseRequest):
    group_id: int              # 小组ID
    student_ids: List[int] = field(default_factory=list)  # 学生ID数组

@dataclass
class SetGroupLeaderRequest(BaseRequest):
    group_id: int   # 学习小组ID
    leader_id: int  # 组长的学生ID（students.id）

@dataclass
class RemoveStudentFromGroupRequest(BaseRequest):
    group_id: int     # 学习小组ID
    student_id: int   # 要移除的学生ID（students.id）

@dataclass
class ListStudyGroupsRequest(BaseRequest):
    class_id: Optional[int] = None  # 班级ID（teacher必传）
    name: Optional[str] = None      # 小组名称（模糊匹配）

@dataclass
class ListGroupMembersRequest(BaseRequest):
    group_id: int  # 学习小组ID

@dataclass
class CreateExamRequest(BaseRequest):
    name: str                # 考试名称
    deadline: datetime       # 截止时间
    admin_password: str      # 管理员或教师口令
    class_id: Optional[int] = None  # 班级ID（可选）
    grade: Optional[int] = None    # 年级（可选）

@dataclass
class UpdateExamRequest(BaseRequest):
    exam_id: int
    name: Optional[str] = None
    deadline: Optional[datetime] = None
    class_id: Optional[int] = None
    grade: Optional[int] = None

@dataclass
class ListExamsRequest(BaseRequest):
    class_id: Optional[int] = None
    grade: Optional[int] = None
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None

@dataclass
class SubmitExamScoreRequest(BaseRequest):
    exam_id: int
    score: float

@dataclass
class UpdateStudentScoreRequest(BaseRequest):
    exam_id: int           # 考试ID
    student_id: int        # 学生在students表中的ID
    new_score: float       # 新的分数
    admin_password: str    # 管理员/教师口令

@dataclass
class ExamScoreRankingRequest(BaseRequest):
    exam_ids: List[int]  # 考试ID数组
    class_id: Optional[int] = None  # 可选，指定班级

@dataclass
class StudentExamResultsRequest(BaseRequest):
    exam_ids: List[int]  # 考试ID数组（所有考试需与学生所在班级或年级匹配）

@dataclass
class UpdateStudentPointsRequest(BaseRequest):
    student_id: int           # 学生在students表中的ID
    points_change: int        # 分值变动（正数为加分，负数为扣分）
    reason: str               # 加分或扣分理由
    admin_password: str       # 教师或管理员口令

@dataclass
class PointsRankingRequest(BaseRequest):
    class_id: int             # 班级ID，用于查询该班级的学生积分排名

@dataclass
class QueryPointsRecordsRequest(BaseRequest):
    start: int = 0                  # 起始位置（从0开始）
    limit: int = 10                 # 查询条目数
    start_time: Optional[datetime] = None  # 开始时间（可选）
    end_time: Optional[datetime] = None    # 结束时间（可选）
    class_id: Optional[int] = None  # 班级ID（可选）
    student_name: Optional[str] = None  # 学生姓名（部分匹配，可选）
    student_number: Optional[str] = None  # 学号（可选）

@dataclass
class PointsStatisticsRequest(BaseRequest):
    class_id: Optional[int] = None 
    group_id: Optional[int] = None
    student_id: Optional[int] = None
    start_time: Optional[datetime] = None 
    end_time: Optional[datetime] = None

@dataclass
class PointsReportRequest(BaseRequest):
    class_id: int
    start_time: datetime
    end_time: datetime

@dataclass
class SendMessageRequest(BaseRequest):
    receiver_ids: List[int]  # 接收者ID数组
    content: str  # 留言内容

@dataclass
class MessageListRequest(BaseRequest):
    offset: int = 0  # 起始位置
    limit: int = 20  # 查询数量
    sender_name: Optional[str] = None  # 发送者姓名（部分匹配）
    receiver_name: Optional[str] = None  # 新增：接收者姓名（部分匹配）
    start_time: Optional[datetime] = None  # 开始时间
    end_time: Optional[datetime] = None  # 结束时间
    only_unread: bool = False  # 是否只看未读

@dataclass
class MessageDetailRequest(BaseRequest):
    message_id: int  # 留言ID（主留言ID）

@dataclass
class ReplyMessageRequest(BaseRequest):
    message_id: int  # 要回复的留言ID（可以是主留言或任何回复）
    content: str     # 回复内容

@dataclass
class StudentDetailRequest(BaseRequest):
    student_id: Optional[int] = None

@dataclass
class ChangePasswordKeyRequest(BaseRequest):
    old_password_key: str
    login_password: str
    new_password_key: str

    def validate(self):
        errors = []
        if not self.old_password_key:
            errors.append("旧口令不能为空")
        if not self.login_password:
            errors.append("登录密码不能为空")
        if not self.new_password_key:
            errors.append("新口令不能为空")
        if self.old_password_key == self.new_password_key:
            errors.append("新口令不能与旧口令相同")
        return errors